package chromosomes;

import logic.Tree;

public class Chromosome {

	private Tree tree;
	private double fitness;
	private double punt;
	private double puntAccumulated;

	public Chromosome() {
		tree = new Tree();
		evaluate();
	}

	public Chromosome(int minDepth, int maxDepth) {
		tree = new Tree(minDepth, maxDepth, null);
		evaluate();
	}

	public Chromosome(Tree tree) {
		setTree(tree.clone());
		evaluate();
	}

	public void evaluate() {
		int corrects = 0;
		boolean[] d = new boolean[4];
		boolean[] a = new boolean[2];
		int max = (int) Math.pow(2, d.length + a.length) - 1;
		for (int i = 0; i < max; i++) {
			plus1(a, d);
			if (optimum(a, d) == tree.evaluate(a, d)) {
				corrects++;
			}
		}
		fitness = corrects;
	}

	public double getFitness() {
		return fitness;
	}

	public double getpAccumulated() {
		return puntAccumulated;
	}

	public double getpSelection() {
		return punt;
	}

	public Tree getTree() {
		return tree;
	}

	public void mutate(double p) {
		tree.mutate(p);
	}

	public void setFitness(double fitness) {
		this.fitness = fitness;
	}

	public void setpAccumulated(double p) {
		puntAccumulated = p;
	}

	public void setpSelection(double p) {
		punt = p;
	}

	public void setTree(Tree tree) {
		this.tree = tree;
	}

	@Override
	protected Object clone() {
		return new Chromosome(tree);
	}

	private boolean optimum(boolean[] as, boolean[] ds) {
		if (as[1] && as[0]) {
			return ds[3];
		} else if (as[1]) {
			return ds[2];
		} else if (as[0]) {
			return ds[1];
		} else {
			return ds[0];
		}
	}

	private void plus1(boolean[] as, boolean[] ds) {
		boolean carry = true;
		for (int i = 0; i < ds.length; i++) {
			boolean aux = carry && ds[i];
			ds[i] = carry ^ ds[i];
			carry = aux;
		}
		for (int i = 0; i < as.length; i++) {
			boolean aux = carry && as[i];
			as[i] = carry ^ as[i];
			carry = aux;
		}
	}

}
